package com.bensonbasement.snorflux.server.world;

import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

import com.bensonbasement.snorflux.utils.Coords;

public class Level /*implements Comparable*/ implements Serializable {
	
	private final Map<Coords,Space> spaceMap;
	private final int levelNum;
	private final World world;
	private final LinkedList<Actor> actors;
//	private Actor nextUpActor = null;
	private Actor previousActor = null;
	private boolean turnOver = true;
	
	public Level(World world, int levelNum) {
		this.world = world;
		this.levelNum = levelNum;
		this.spaceMap = new HashMap<Coords,Space>();
		this.actors = new LinkedList<Actor>();
	}
	
	public void addSpace(Space space) {
		assert space.getLevel() == this;
		assert ! this.spaceMap.containsKey(space.getCoords());
		this.spaceMap.put(space.getCoords(), space);
	}
	
	public Space getSpace(Coords coords) {
		return this.spaceMap.get(coords);
	}
	
	public Space getSpace(int x, int y) {
		return this.getSpace(new Coords(x,y));
	}

	public int getLevelNum() {
		return levelNum;
	}

//	/**
//	 * Used to help order the levels.
//	 */
//	@Override
//	public int compareTo(Object other) {
//		Level otherLevel = (Level) other;
//		return new Integer(this.levelNum).compareTo(new Integer(otherLevel.levelNum));
//	}

	public World getWorld() {
		return world;
	}
	
	public void addActor(Actor actor) {
		this.addActor(actor,false);
	}
	
	public void addActor(Actor actor, boolean endOfTurn) {
		if (endOfTurn) {
			this.actors.addLast(actor);
		}
		else {
			this.actors.addFirst(actor);
		}
	}
	
	public void removeActor(Actor actor) {
		if (actor == this.previousActor) {
			int newPreviousActorIndex = this.actors.indexOf(this.previousActor) - 1;
			if (newPreviousActorIndex < 0) {
				this.previousActor = null;
			}
			else {
				this.previousActor = this.actors.get(newPreviousActorIndex);
			}
		}
		this.actors.remove(actor);
	}
	
	/*
	 * Start the turn for this level.
	 */
	public void startTurn() {
		this.turnOver = false;
	}
	
	public Actor nextActor() {
		if (this.turnOver) {
			throw new RuntimeException("Shouldn't call nextActor after level turn is finished.");
		}
		else {
			Actor next;
			if (this.previousActor == null) {
				next = this.actors.getFirst();
			}
			else {
				int nextActorIndex = this.actors.indexOf(this.previousActor) + 1;
				if (nextActorIndex < this.actors.size()) {
					next = this.actors.get(nextActorIndex);
				}
				else {
					this.turnOver = true;
					next = null;
				}
			}
			this.previousActor = next;
			return next;
		}
	}
	
	public void forceInfoRefresh(WorldElement element) {
		for (BrainTeam brainTeam : this.getAllBrainTeamsSeeingLevel()) {
			brainTeam.updateInfo(element);
		}
	}
	
	public Set<BrainTeam> getAllBrainTeamsSeeingLevel() {
		HashSet<BrainTeam> retVal = new HashSet<BrainTeam>();
		for (Actor actor : this.actors) {
			BrainTeam brainTeam = actor.getBrainTeam();
			if (brainTeam != null) {
				retVal.add(brainTeam);
			}
		}
		return retVal;
	}
	
	public void animateAll() {
		for (Space space : this.spaceMap.values()) {
			for (WorldElement element : space.getAllWorldElements()) {
				element.animate();
			}
		}
	}
}
